package com.mall.huohuo.process;

import com.google.common.base.Stopwatch;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;

/**
 * 节点处理的抽象类
 * @author zycoding
 * @version AbstractProcessNode.java, v 0.1 2020-08-18 20:30 zycoding
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
@Slf4j
public abstract class AbstractProcessNode implements Node {

    /**
     * 执行之前校验参数
     * @param nodeContext 节点上下文
     * @return 是否校验通过
     */
    protected boolean validate(NodeContext nodeContext){
        return true;
    }

    /**
     * 执行之前的操作
     * @param nodeContext 节点上下文
     */
    protected void beforeInvoke(NodeContext nodeContext) {

    }

    /**
     * 执行之后的操作操作
     * @param nodeContext 节点上下文
     */
    protected void afterInvoke(NodeContext nodeContext){

    }
    /**
     * 节点处理
     * @param nodeContext 节点上下文信息
     */
    @Override
    public void invoke(final NodeContext nodeContext) {
        try {
           long startTime = System.currentTimeMillis();
            if (validate(nodeContext)) {
                beforeInvoke(nodeContext);

                doInvoke(nodeContext);

                afterInvoke(nodeContext);

                if (!isFinish(nodeContext)) {
                    nodeContext.getPipeline().invoke(nodeContext);
                }
            }
            long endTime = System.currentTimeMillis();

            log.info("invoke processName={} cost time {}", nodeContext.getProcessName(), endTime - startTime);
        } catch (Exception e) {
            doCatch(e);
        }finally {
            doFinally(nodeContext);
        }
    }

    /**
     * 是否已经执行完毕了，执行完毕了之后就不在执行了
     * @param nodeContext 节点上下文
     * @return 是否已经执行完毕,默认false
     */
    protected boolean isFinish(NodeContext nodeContext){
        return false;
    }

    /**
     * 执行
     * @param nodeContext 节点上下文
     */
    protected  abstract  void doInvoke(NodeContext nodeContext);

    /**
     * 发生异常的时候会执行方法
     * @param exception 异常
     */
    protected void doCatch(Exception exception){
        throw new RuntimeException(exception);
    }

    /**
     * 最终要执行的方法。finally
     * @param nodeContext 节点上下文
     */
    protected void doFinally(NodeContext nodeContext) {

    }
}
